using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using OhioState.Graphics.IMaterial;
using OhioState.Graphics.IDrawable;
using OhioState.Graphics.IAssetManaged;


namespace OhioStateVolumeRenderer
{    
    class DrawableMaterialGrid : DataGridView
    {
        public DrawableMaterialGrid() : base()
        {
            this.CurrentCellDirtyStateChanged += new System.EventHandler(this.CurrentCellDirtyStateChangedHandler);
            this.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(this.CellValueChangedHandler);
            this.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(this.DataErrorHandler);
            this.Validating += new System.ComponentModel.CancelEventHandler(this.ValidatingHandler);
        }
        
        /// <summary>
        /// Set the data source to the comboboxes in the grid.
        /// </summary>
        /// <param name="materialList"></param> the list of materials that will be available in the combos
        public void SetMaterialList(List<IMaterial> materialList)
        {
            DataGridViewComboBoxColumn comboColumn = this.Columns[1] as DataGridViewComboBoxColumn;
            comboColumn.DataSource = null;
            comboColumn.DataSource = materialList;
        }

        private void CellValueChangedHandler(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == 1 && e.RowIndex >= 0)
            {
                object obj = this.Rows[e.RowIndex].Cells[0].Value;
                if (obj is IDrawable)
                {
                    IDrawable drawableObj = obj as IDrawable;
                    string materialName = this.Rows[e.RowIndex].Cells[1].Value as string;

                    List<IAssetManaged> assets = AssetManager.Instance.GetItem(materialName);
                    foreach (IAssetManaged asset in assets)
                    {
                        IMaterial material = asset as IMaterial;
                        if (material != null)
                        {
                            drawableObj.Material = material;
                            this.Rows[e.RowIndex].Cells[1].Value = drawableObj.Material;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Fire CellValueChanged event via CommitEdit method:
        /// taken from Microsoft docs on CurrentCellDirtyStateChanged event;
        /// Before adding this CellValueChanged event was fired only when combobox changed focus,
        /// which is not the correct behavior - we want this to happen any time we select material
        /// in a combobox.
        /// </summary>
        private void CurrentCellDirtyStateChangedHandler(object sender, EventArgs e)
        {
            if (this.IsCurrentCellDirty)
            {
                this.CommitEdit(DataGridViewDataErrorContexts.Commit);
            }
        }

        /// <summary>
        /// Hack - just ignore the data error which happens when new materials are
        /// added/selected to the comboboxes.
        /// Setting DataSource to null before updating the materials list
        /// helps only in some cases, that's why we have to use this method.
        /// </summary>
        private void DataErrorHandler(object sender, DataGridViewDataErrorEventArgs e)
        {
        }

        private void ValidatingHandler(object sender, CancelEventArgs e)
        {
        }
    }
}
